//################################################################################
// MIT License
// Copyright (c) 2024 ZhangYihua
//
// Change Logs:
// Date           Author       Notes
// 2023-02-06     ZhangYihua   first version
//
// Description  : 
//################################################################################

//CRC-4     x4+x+1                  3           ITU G.704
//CRC-7	    x7+x3+1  	            9 	        G.707 J0
//CRC-8	    x8+x5+x4+1	            31	        DS18B20
//CRC-12    x12+x11+x3+x2+x+1       80F
//CRC-16    x16+x15+x2+1            8005        IBM SDLC
//CRC-CCITT x16+x12+x5+1            1021        ISO HDLC, ITU X.25, V.34/V.41/V.42, PPP-FCS,ZigBee
//CRC-32    x32+x26+x23+...+x2+x+1  04C11DB7    ZIP, RAR, IEEE 802 LAN/FDDI, IEEE 1394, PPP-FCS
//CRC-32C   x32+x28+x27+...+x8+x6+1 1EDC6F41    SCTP

// CRC_16 is for USA; CRC_CCITT is for Europe

// RFC1662 HDLC FCS16   : TYPE="CRC_CCITT", FIRST="LSB", CW=16, initial=0xFFFF,     GoodFCS = 0xF0B8
// GFP FCS16            : TYPE="CRC_CCITT", FIRST="MSB", CW=16, initial=0x0000,     GoodFCS = 0x0000

// RFC1662 HDLC FCS32   : TYPE="CRC_32",    FIRST="LSB", CW=32, initial=0xFFFFFFFF, GoodFCS = 0xDEBB20E3
// GFP FCS32            : TYPE="CRC_32",    FIRST="MSB", CW=32, initial=0xFFFFFFFF, GoodFCS = 0xC704DD7B
// 802.3 MAC FCS32      : TYPE="CRC_32",    FIRST="LSB", CW=32, initial=0xFFFFFFFF, GoodFCS = 0xDEBB20E3

// calculate next crc value according to current data and crc value
module crc_calc #(
parameter           DW                      = 8,
parameter           TYPE                    = "CRC_CCITT",  // "CRC_16" "CRC_32" "CRC_4" "CRC_7" "CRC_8" "CRC_12" "CRC_32C"
parameter           FIRST                   = "LSB",        // bit[0] is transmitted first in serial mode
//parameter           FIRST                   = "MSB",        // bit[DW-1]/bit[CW-1] is transmitted first in serial mode
parameter           CW                      = 16            // set CW according to TYPE
) ( 
input               [DW-1:0]                dat_cur,     // current data
input               [CW-1:0]                crc_cur,     // current crc
output  reg         [CW-1:0]                crc_nxt      // next crc
);

//################################################################################
// define local varialbe and localparam
//################################################################################
localparam [CW-1:0] G                       = (TYPE=="CRC_4")     ?  4'h3 :         // G(x)=x4+x+1
                                              (TYPE=="CRC_7")     ?  7'h9 :         // G(x)=x7+x3+1
                                              (TYPE=="CRC_8")     ?  8'h31 :        // G(x)=x8+x5+x4+1
                                              (TYPE=="CRC_12")    ? 12'h80F :       // G(x)=x12+x11+x3+x2+x+1
                                              (TYPE=="CRC_16")    ? 16'h8005 :      // G(x)=x16+x15+x2+1
                                              (TYPE=="CRC_CCITT") ? 16'h1021 :      // G(x)=x16+x12+x5+1
                                              (TYPE=="CRC_32")    ? 32'h04C11DB7 :  // G(x)=x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1
                                              (TYPE=="CRC_32C")   ? 32'h1EDC6F41 :  // G(x)=x32+x28+x27+x26+x25+x23+x22+x20+x19+x18+x14+x13+x11+x10+x9+x8+x6+1
                                                                    {CW{1'b0}};

localparam [CW-1:0] GR                      = reverse_f(G);

//################################################################################
// main
//################################################################################

always@(*) begin:ITE
    integer i;
    reg[CW-1:0] ct;
    reg fb;

    ct = crc_cur;
    if (FIRST=="MSB") begin
        for(i=DW-1;i>=0;i=i-1) begin
            fb = dat_cur[i] ^ ct[CW-1];
            ct = (ct<<1) ^ ({CW{fb}} & G);
        end
    end else if (FIRST=="LSB") begin
        for(i=0;i<DW;i=i+1) begin
            fb = dat_cur[i] ^ ct[0];
            ct = (ct>>1) ^ ({CW{fb}} & GR);
        end
    end
    
    crc_nxt = ct;
end

function [CW-1:0] reverse_f;
    input [CW-1:0] g;
    integer i;
    begin
        for (i=0; i<CW; i=i+1) begin
            reverse_f[i] = g[CW-1-i];
        end
    end
endfunction

//################################################################################
// ASSERTION
//################################################################################

`ifdef CBB_ASSERT_ON
// synopsys translate_off


// synopsys translate_on
`endif

endmodule
